#!/usr/bin/env python

import struct
import hashlib
import math
import time
import urllib

from StringIO import StringIO
from google.appengine.api import urlfetch

import datamodel
from settings import Settings

def queueThumbnails(post, image_data):
  post.image_filename = str(int(time.mktime(post.date.timetuple()))) + str(post.postid)
  if post.image_extension == '.gif':
    post.thumb_filename = post.image_filename + 's.gif'
  else:
    # PNGs and JPGs are both thumbnailed as JPG files
    post.thumb_filename = post.image_filename + 's.jpg'
  post.image_filename = post.image_filename + post.image_extension
  
  queueThumbnailDaemon(False, post.image, image_data, post.thumb_width, post.thumb_height, post.image_filename)
  queueThumbnailDaemon(True, post.image, image_data, post.thumb_catalog_width, post.thumb_catalog_height, post.image_filename)
  
def queueThumbnailDaemon(catalog, image_key, image_data, thumb_width, thumb_height, filename):
  if catalog:
    callback = 'http://' + Settings.APP_NAME + '.appspot.com/finish_c'
  else:
    callback = 'http://' + Settings.APP_NAME + '.appspot.com/finish'
    
  query = urllib.urlencode({
      'id':       image_key,
      'size':     str(thumb_width) + 'x' + str(thumb_height),
      'action':   'avatar',
      'quality':  '85',
      'callback': callback,
      'file_name': filename,
  })
  try:
    resp = urlfetch.fetch('http://resizer.movq.net/resizer/resize?%s' % query, payload=image_data, method=urlfetch.POST, headers={}, allow_truncated=False)
    if resp.status_code != 200:
      logging.error("failed to schedule image resize for img %s, code=%i msg=%.60r" % (image_key, resp.status_code, resp.content) )
  except urlfetch.DownloadError:
      logging.error("failed to schedule image resize for img %s" % (image_key) )
  
def checkImageNotDuplicate(image):
  image_hex = getImageHex(image)
  post = datamodel.Post.all().filter('image_hex = ', image_hex).get()
  if post:
    if post.parentid:
      return False, post.parentid, post.postid
    else:
      return False, post.postid, post.postid
  else:
    return True, 0, 0
  
def getThumbDimensions(width, height, maxsize):
  wratio = (float(maxsize) / float(width))
  hratio = (float(maxsize) / float(height))
  
  if (width <= maxsize) and (height <= maxsize):
    return width, height
  else:
    if (wratio * height) < maxsize:
      thumb_height = math.ceil(wratio * height)
      thumb_width = maxsize
    else:
      thumb_width = math.ceil(hratio * width)
      thumb_height = maxsize
  
  return int(thumb_width), int(thumb_height)

def getImageHex(data):
  return hashlib.sha224(data).hexdigest()

def getImage(key):
  image = datamodel.Image.get(key)
  
  return image

def displayImage(self, key, mime, thumb=False, thumbcat=False):
  image = getImage(key)
  if image:
    self.response.headers['Expires'] = 'Thu, 15 Apr 2010 20:00:00 GMT'
    self.response.headers['Cache-Control'] = 'max-age=3600,public'

    if (thumbcat or thumb) and image.thumb_data:
      if str(mime) == 'image/png':
        self.response.headers['Content-Type'] = 'image/jpeg'
      else:
        self.response.headers['Content-Type'] = str(mime)

      if thumbcat and image.thumb_catalog_data:
        self.response.out.write(image.thumb_catalog_data)
      else:
        self.response.out.write(image.thumb_data)
    else:
      self.response.headers['Content-Type'] = str(mime)

      self.response.out.write(image.data)

def getImageInfo(data):
    data = str(data)
    size = len(data)
    height = -1
    width = -1
    content_type = ''

    # handle GIFs
    if (size >= 10) and data[:6] in ('GIF87a', 'GIF89a'):
        # Check to see if content_type is correct
        content_type = 'image/gif'
        w, h = struct.unpack("<HH", data[6:10])
        width = int(w)
        height = int(h)

    # See PNG 2. Edition spec (http://www.w3.org/TR/PNG/)
    # Bytes 0-7 are below, 4-byte chunk length, then 'IHDR'
    # and finally the 4-byte width, height
    elif ((size >= 24) and data.startswith('\211PNG\r\n\032\n')
          and (data[12:16] == 'IHDR')):
        content_type = 'image/png'
        w, h = struct.unpack(">LL", data[16:24])
        width = int(w)
        height = int(h)

    # Maybe this is for an older PNG version.
    elif (size >= 16) and data.startswith('\211PNG\r\n\032\n'):
        # Check to see if we have the right content type
        content_type = 'image/png'
        w, h = struct.unpack(">LL", data[8:16])
        width = int(w)
        height = int(h)

    # handle JPEGs
    elif (size >= 2) and data.startswith('\377\330'):
        content_type = 'image/jpeg'
        jpeg = StringIO(data)
        jpeg.read(2)
        b = jpeg.read(1)
        try:
            while (b and ord(b) != 0xDA):
                while (ord(b) != 0xFF): b = jpeg.read
                while (ord(b) == 0xFF): b = jpeg.read(1)
                if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
                    jpeg.read(3)
                    h, w = struct.unpack(">HH", jpeg.read(4))
                    break
                else:
                    jpeg.read(int(struct.unpack(">H", jpeg.read(2))[0])-2)
                b = jpeg.read(1)
            width = int(w)
            height = int(h)
        except struct.error:
            pass
        except ValueError:
            pass

    return content_type, width, height
